// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
#include <mach/csp.h>
#include "isp_csp.h"

/* #define ENABLE_TRACE */
#include <mach/debug.h>

#define ISP_BPAT_RGGB				0x00000001
#define ISP_BPAT_GRBG				0x00000002
#define ISP_BPAT_GBRG				0x00000004
#define ISP_BPAT_BGGR				0x00000008

#define ISP_CLK_CTRL				0x10
#define ISP_DATA_PATH_CTRL			0x18

#define ISP_CTRL				0x400
#define ISP_ACQ_CFG				0x404
#define ISP_INT_EN_MASK				0x5bc
#define ISP_INT_STATUS				0x5c0
#define ISP_INT_CLR				0x5c8

#define ISP_IPPU_CTRL				0x1100
#define ISP_TNR_INPUT_MEM_Y_ADD			0x1138
#define ISP_TNR_INPUT_MEM_CB_ADD		0x113C
#define ISP_TNR_INPUT_MEM_CR_ADD		0x1140
#define ISP_TNR_OUTPUT_MEM_Y_ADD		0x1144
#define ISP_TNR_OUTPUT_MEM_CB_ADD		0x1148
#define ISP_TNR_OUTPUT_MEM_CR_ADD		0x114C

#define ISP_MAINPATH_CTRL			0xC00
#define ISP_MAINPATH_SCALE_HY			0xC04
#define ISP_MAINPATH_SCALE_HCB			0xC08
#define ISP_MAINPATH_SCALE_HCR			0xC0C
#define ISP_MAINPATH_SCALE_VY			0xC10
#define ISP_MAINPATH_SCALE_VC			0xC14

#define ISP_SUBPATH_CTRL			0x1000
#define ISP_SUBPATH_SCALE_HY			0x1004
#define ISP_SUBPATH_SCALE_HCB			0x1008
#define ISP_SUBPATH_SCALE_HCR			0x100C
#define ISP_SUBPATH_SCALE_VY			0x1010
#define ISP_SUBPATH_SCALE_VC			0x1014

#define ISP_DMA_CTRL				0x1400
#define ISP_DMA_CTRL2				0x1404

#define ISP_DMA_MAINPATH_Y_ADD			0x1408
#define ISP_DMA_MAINPATH_Y_SIZE			0x140c
#define ISP_DMA_MAINPATH_CB_ADD			0x141c
#define ISP_DMA_MAINPATH_CB_SIZE		0x1420
#define ISP_DMA_MAINPATH_CR_ADD			0x142c
#define ISP_DMA_MAINPATH_CR_SIZE		0x1430

#define ISP_DMA_SUBPATH_Y_ADD			0x143c
#define ISP_DMA_SUBPATH_Y_SIZE			0x1440
#define ISP_DMA_SUBPATH_CB_ADD			0x1450
#define ISP_DMA_SUBPATH_CB_SIZE			0x1454
#define ISP_DMA_SUBPATH_CR_ADD			0x1460
#define ISP_DMA_SUBPATH_CR_SIZE			0x1464

#define ISP_DMA_Y_PIC_START_ADD			0x14C8
#define ISP_DMA_Y_PIC_WIDTH			0x14CC
#define ISP_DMA_Y_PIC_LEN			0x14D0
#define ISP_DMA_Y_PIC_SIZE			0x14D4
#define ISP_DMA_INT_STATUS_MASK		0x1500
#define ISP_DMA_INT_CLR				0x1504
#define ISP_DMA_INT_EN_MASK			0x1508
#define ISP_DMA_STATUS				0x150C
#define ISP_DMA_STATUS_CLR			0x1510
#define ISP_DMA_START_CTRL			0x1520
#define ISP_DMA_START				0x1524

#define ISP_DMA_DS					0x15a8

#define ISP_ANTI_SHAKE_STAT_MEM_ADD		0x2f24
#define ISP_BGM_STAT_MEM_ADD			0x2f88

struct isp_regs_list_desc {
	u32 start;
	u32 end;
} regs_list[] = {
	{0x0000, 0x0018},
	{0x0200, 0x0224},
	{0x0300, 0x0314},
	{0x0400, 0x0650},
	{0x0660, 0x0674},
	{0x0680, 0x068c},
	{0x0800, 0x0810},
	{0x0c00, 0x0c54},
	{0x1000, 0x1054},
	{0x1400, 0x15a8},
	{0x2000, 0x2038},
	{0x2200, 0x220c},
	{0x2224, 0x2260},
	{0x2300, 0x2330},
	{0x2400, 0x246c},
	{0x2500, 0x254c},
	{0x2580, 0x2598},
	{0x0690, 0x0698},
	{0x2600, 0x2610},
	{0x2700, 0x2744},
	{0x2800, 0x2870},
	{0x2900, 0x2968},
	{0x2a00, 0x2b30},
	{0x2c00, 0x2d24},
	{0x2f00, 0x2f28},
	{0x2f80, 0x2f8c},
	{0x2e00, 0x2e50},
	{0x1100, 0x11a8},
};

u32 isp_reg_read(void *base, u32 reg)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p,reg=0x%08x\n", base, reg);
	val = READREG32((unsigned long)base + reg);
	PRT_TRACE_END("val=0x%08x\n", val);

	return val;
}

void isp_reg_write(void *base, u32 reg, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,reg=0x%08x,val=%08x\n",
			base, reg, val);
	WRITEREG32((unsigned long)base + reg, val);
	PRT_TRACE_END("\n");
}

void isp_reg_clr(void *base, u32 reg, u32 clr_bits)
{
	u32 v;

	PRT_TRACE_BEGIN("base=%p,reg=0x%08x,set_bits=%08x\n",
			base, reg, clr_bits);
	v = isp_reg_read(base, reg);
	isp_reg_write(base, reg, v & ~clr_bits);
	PRT_TRACE_END("\n");
}

void isp_reg_set(void *base, u32 reg, u32 set_bits)
{
	u32 v;

	PRT_TRACE_BEGIN("base=%p,reg=0x%08x,set_bits=%08x\n",
			base, reg, set_bits);
	v = isp_reg_read(base, reg);
	isp_reg_write(base, reg, v | set_bits);
	PRT_TRACE_END("\n");
}

void isp_reg_clr_set(void *base, u32 reg,
		u32 clr_bits, u32 set_bits)
{
	u32 v;

	PRT_TRACE_BEGIN("base=%p,reg=0x%08x,clr_bits=%08x,set_bits=%08x\n",
			base, reg, clr_bits, set_bits);
	v = isp_reg_read(base, reg);
	isp_reg_write(base, reg, (v & ~clr_bits) | set_bits);
	PRT_TRACE_END("\n");
}

/*  config isp clock enable */
void csp_isp_cfg_clk_en(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_CLK_CTRL, 0x215b);
	PRT_TRACE_END("\n");
}

/*  config isp data path */
void csp_isp_data_path_ctrl(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_DATA_PATH_CTRL, 0x4d);
	PRT_TRACE_END("\n");
}

/* enable or disable isp */
void csp_isp_enable(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	if (val) {
		isp_reg_set(base, ISP_CTRL, (1 << 9) | (1 << 10) | (1 << 8));
		isp_reg_set(base, ISP_CTRL, (1 << 4) | (1 << 0));
	} else {
		isp_reg_clr(base, ISP_CTRL, 1 << 0);
	}
	PRT_TRACE_END("\n");
}

/* config isp */
void csp_isp_set_ctrl(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_CTRL, 0x00020ff7);
	PRT_TRACE_END("\n");
}

/* config isp acq */
void csp_isp_acq_cfg(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_set(base, ISP_ACQ_CFG, val);
	PRT_TRACE_END("\n");
}

/* get isp interrupt status */
u32 csp_isp_get_isp_int_status(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_INT_STATUS);
	PRT_TRACE_END("val=0x%08x\n", val);

	return val;
}

/* check if isp occur data loss error */
u32 csp_isp_check_data_loss(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_INT_STATUS);
	val = (val >> 2) & 1;
	PRT_TRACE_END("val=%u\n", val);

	return val;
}

/* check if isp off */
u32 csp_isp_check_off(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_INT_STATUS);
	val = (val >> 0) & 1;
	PRT_TRACE_END("val=%u\n", val);

	return val;
}

/* enable or disable isp data loss interrupt */
void csp_isp_en_data_loss(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	if (val)
		isp_reg_set(base, ISP_INT_EN_MASK, 1 << 2);
	else
		isp_reg_clr(base, ISP_INT_EN_MASK, 1 << 2);
	PRT_TRACE_END("\n");
}

/* disable all isp interrupt */
void csp_isp_disable_isp_int(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_INT_EN_MASK, 0);
	PRT_TRACE_END("\n");
}

/* clear isp interrupt */
void csp_isp_clr_isp_int(void *base, u32 imask)
{
	PRT_TRACE_BEGIN("base=%p,imask=0x%08x\n", base, imask);
	isp_reg_write(base, ISP_INT_CLR, imask);
	PRT_TRACE_END("\n");
}

/* set isp tnr default control */
void csp_isp_ippu_ctrl(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_set(base, ISP_IPPU_CTRL, 0x3 << 11);
	PRT_TRACE_END("\n");
}

/* set isp tnr default control */
u32 csp_isp_ippu_is_enabled(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_IPPU_CTRL);
	PRT_TRACE_END("\n");

	return val & (1 << 31);
}

/* enable or disable ippu */
void csp_isp_enable_ippu(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	if (val)
		isp_reg_set(base, ISP_IPPU_CTRL, 1 << 31);
	else
		isp_reg_clr(base, ISP_IPPU_CTRL, 1 << 31);
	PRT_TRACE_END("\n");
}

/* set isp tnr input address */
void csp_isp_set_tnr_input_add(void *base, dma_addr_t y_add,
			dma_addr_t cb_add, dma_addr_t cr_add)
{
	PRT_TRACE_BEGIN("base=%p,y_add=0x%08x,cb_add=0x%08x,cr_add=0x%08x\n",
			base, y_add, cb_add, cr_add);
	isp_reg_write(base, ISP_TNR_INPUT_MEM_Y_ADD, y_add);
	isp_reg_write(base, ISP_TNR_INPUT_MEM_CB_ADD, cb_add);
	isp_reg_write(base, ISP_TNR_INPUT_MEM_CR_ADD, cr_add);
	PRT_TRACE_END("\n");
}

/* set isp tnr output address */
void csp_isp_set_tnr_output_add(void *base, dma_addr_t y_add,
			dma_addr_t cb_add, dma_addr_t cr_add)
{
	PRT_TRACE_BEGIN("base=%p,y_add=0x%08x,cb_add=0x%08x,cr_add=0x%08x\n",
			base, y_add, cb_add, cr_add);
	isp_reg_write(base, ISP_TNR_OUTPUT_MEM_Y_ADD, y_add);
	isp_reg_write(base, ISP_TNR_OUTPUT_MEM_CB_ADD, cb_add);
	isp_reg_write(base, ISP_TNR_OUTPUT_MEM_CR_ADD, cr_add);
	PRT_TRACE_END("\n");
}

/* enable or disable isp main path dma */
void csp_isp_dma_main_path_enable(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	if (val)
		isp_reg_set(base, ISP_DMA_CTRL, 1 << 0);
	else
		isp_reg_clr(base, ISP_DMA_CTRL, 1 << 0);
	PRT_TRACE_END("\n");
}

void csp_isp_dma_config_update(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_DMA_CTRL2, 0x10);
	PRT_TRACE_END("\n");
}

/* enable or disable isp sub path dma */
void csp_isp_dma_sub_path_enable(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	if (val)
		isp_reg_set(base, ISP_DMA_CTRL, 1 << 1);
	else
		isp_reg_clr(base, ISP_DMA_CTRL, 1 << 1);
	PRT_TRACE_END("\n");
}

/* isp dma default control */
void csp_isp_dma_ctrl(void *base, u32 fmt)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_DMA_CTRL, 0x283a6000 | (fmt<<22) | (fmt<<24));
	PRT_TRACE_END("\n");
}

/* set isp main path output address */
void csp_isp_set_dma_main_path_add(void *base, dma_addr_t y_add,
			dma_addr_t cb_add, dma_addr_t cr_add)
{
	PRT_TRACE_BEGIN("base=%p,y_add=0x%08x,cb_add=0x%08x,cr_add=0x%08x\n",
			base, y_add, cb_add, cr_add);
	isp_reg_write(base, ISP_DMA_MAINPATH_Y_ADD, y_add);
	isp_reg_write(base, ISP_DMA_MAINPATH_CB_ADD, cb_add);
	isp_reg_write(base, ISP_DMA_MAINPATH_CR_ADD, cr_add);
	PRT_TRACE_END("\n");
}

/* set isp sub path output address */
void csp_isp_set_dma_sub_path_add(void *base, dma_addr_t y_add,
			dma_addr_t cb_add, dma_addr_t cr_add)
{
	PRT_TRACE_BEGIN("base=%p,y_add=0x%08x,cb_add=0x%08x,cr_add=0x%08x\n",
			base, y_add, cb_add, cr_add);
	isp_reg_write(base, ISP_DMA_SUBPATH_Y_ADD, y_add);
	isp_reg_write(base, ISP_DMA_SUBPATH_CB_ADD, cb_add);
	isp_reg_write(base, ISP_DMA_SUBPATH_CR_ADD, cr_add);
	PRT_TRACE_END("\n");
}

/* set isp main path size */
void csp_isp_set_dma_main_path_y_size(void *base, u32 y_size,
			u32 cb_size, u32 cr_size)
{
	PRT_TRACE_BEGIN("base=%p,y_size=0x%08x,cb_size=0x%08x,cr_size=0x%08x\n",
			base, y_size, cb_size, cr_size);
	isp_reg_write(base, ISP_DMA_MAINPATH_Y_SIZE, y_size);
	isp_reg_write(base, ISP_DMA_MAINPATH_CB_SIZE, cb_size);
	isp_reg_write(base, ISP_DMA_MAINPATH_CR_SIZE, cr_size);
	PRT_TRACE_END("\n");
}

/* set isp sub path size */
void csp_isp_set_dma_sub_path_y_size(void *base, u32 y_size,
			u32 cb_size, u32 cr_size)
{
	PRT_TRACE_BEGIN("base=%p,y_size=0x%08x,cb_size=0x%08x,cr_size=0x%08x\n",
			base, y_size, cb_size, cr_size);
	isp_reg_write(base, ISP_DMA_SUBPATH_Y_SIZE, y_size);
	isp_reg_write(base, ISP_DMA_SUBPATH_CB_SIZE, cb_size);
	isp_reg_write(base, ISP_DMA_SUBPATH_CR_SIZE, cr_size);
	PRT_TRACE_END("\n");
}

/* config main path scale */
void csp_isp_set_main_path_scale(void *base, u32 inw, u32 inh,
			u32 outw, u32 outh)
{
	u32 scale_hy   = 0;
	u32 scale_hcb  = 0;
	u32 scale_hcr  = 0;
	u32 scale_vy   = 0;
	u32 scale_vc   = 0;

	PRT_TRACE_BEGIN("base=%p,outw=%d,outh=%d\n", base, outw, outh);

	scale_hy = (((outw - 1) << 16) / (inw - 1)) + 1;
	scale_hcb = (((outw - 1) << 16) / (inw - 1)) + 1;
	scale_hcr = (((outw - 1) << 16) / (inw - 1)) + 1;

	scale_vy = (((outh - 1) << 16) / (inh - 1)) + 1;
	scale_vc = (((outh / 2 - 1) << 16) / (inh - 1)) + 1;

	isp_reg_write(base, ISP_MAINPATH_SCALE_HY, scale_hy);
	isp_reg_write(base, ISP_MAINPATH_SCALE_HCB, scale_hcb);
	isp_reg_write(base, ISP_MAINPATH_SCALE_HCR, scale_hcr);
	isp_reg_write(base, ISP_MAINPATH_SCALE_VY, scale_vy);
	isp_reg_write(base, ISP_MAINPATH_SCALE_VC, scale_vc);

	if ((inw == outw) && (inh == outh)) {
		isp_reg_write(base, ISP_MAINPATH_CTRL, 0x200);
		isp_reg_set(base, ISP_DMA_DS, 0x1 << 0);
	} else if (inw == outw) {
		isp_reg_write(base, ISP_MAINPATH_CTRL, 0x20c);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 0);
	} else if (inh == outh) {
		isp_reg_write(base, ISP_MAINPATH_CTRL, 0x20b);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 0);
	} else {
		isp_reg_write(base, ISP_MAINPATH_CTRL, 0x20f);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 0);
	}

	PRT_TRACE_END("\n");
}

/* config sub path scale */
void csp_isp_set_sub_path_scale(void *base, u32 inw, u32 inh,
			u32 outw, u32 outh)
{
	u32 scale_hy   = 0;
	u32 scale_hcb  = 0;
	u32 scale_hcr  = 0;
	u32 scale_vy   = 0;
	u32 scale_vc   = 0;

	PRT_TRACE_BEGIN("base=%p,outw=%d,outh=%d\n", base, outw, outh);

	scale_hy = (((outw - 1) << 16) / (inw - 1)) + 1;
	scale_hcb = (((outw - 1) << 16) / (inw - 1)) + 1;
	scale_hcr = (((outw - 1) << 16) / (inw - 1)) + 1;

	scale_vy = (((outh - 1) << 16) / (inh - 1)) + 1;
	scale_vc = (((outh / 2 - 1) << 16) / (inh - 1)) + 1;

	isp_reg_write(base, ISP_SUBPATH_SCALE_HY, scale_hy);
	isp_reg_write(base, ISP_SUBPATH_SCALE_HCB, scale_hcb);
	isp_reg_write(base, ISP_SUBPATH_SCALE_HCR, scale_hcr);
	isp_reg_write(base, ISP_SUBPATH_SCALE_VY, scale_vy);
	isp_reg_write(base, ISP_SUBPATH_SCALE_VC, scale_vc);

	if ((inw == outw) && (inh == outh)) {
		isp_reg_write(base, ISP_SUBPATH_CTRL, 0x200);
		isp_reg_set(base, ISP_DMA_DS, 0x1 << 1);
	} else if (inw == outw) {
		isp_reg_write(base, ISP_SUBPATH_CTRL, 0x20c);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 1);
	} else if (inh == outh) {
		isp_reg_write(base, ISP_SUBPATH_CTRL, 0x20b);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 1);
	} else {
		isp_reg_write(base, ISP_SUBPATH_CTRL, 0x20f);
		isp_reg_clr(base, ISP_DMA_DS, 0x1 << 1);
	}

	PRT_TRACE_END("\n");
}

void csp_isp_set_dma_y_pic_start_add(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_DMA_Y_PIC_START_ADD, val);
	PRT_TRACE_END("\n");
}

/* set isp dma y component width */
void csp_isp_set_dma_y_pic_width(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_DMA_Y_PIC_WIDTH, val);
	PRT_TRACE_END("\n");
}

/* set isp dma y component length */
void csp_isp_set_dma_y_pic_len(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_DMA_Y_PIC_LEN, val);
	PRT_TRACE_END("\n");
}

/* set isp dma y component size */
void csp_isp_set_dma_y_pic_size(void *base, u32 val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_DMA_Y_PIC_SIZE, val);
	PRT_TRACE_END("\n");
}

/* get isp dma interrupt status */
u32 csp_isp_get_dma_int_status(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_DMA_INT_STATUS_MASK);
	PRT_TRACE_END("val=0x%08x\n", val);

	return val;
}

/* clear isp dma interrupt status */
void csp_isp_clr_dma_int(void *base, u32 imask)
{
	PRT_TRACE_BEGIN("base=%p,imask=0x%08x\n", base, imask);
	isp_reg_write(base, ISP_DMA_INT_CLR, imask);
	PRT_TRACE_END("\n");
}

/* disable all isp dma interrupt */
void csp_isp_disable_dma_int(void *base)
{
	PRT_TRACE_BEGIN("base=%p\n", base);
	isp_reg_write(base, ISP_DMA_INT_EN_MASK, 0);
	PRT_TRACE_END("\n");
}

/* get isp dma status */
u32 csp_isp_get_dma_status(void *base)
{
	u32 val;

	PRT_TRACE_BEGIN("base=%p\n", base);
	val = isp_reg_read(base, ISP_DMA_STATUS);
	PRT_TRACE_END("val=0x%08x\n", val);

	return val;
}

/* clear isp dma status */
void csp_isp_clr_dma_status(void *base, u32 status)
{
	PRT_TRACE_BEGIN("base=%p,status=0x%08x\n", base, status);
	isp_reg_write(base, ISP_DMA_STATUS_CLR, status);
	PRT_TRACE_END("\n");
}

/* set anti shake address for hardware */
void csp_isp_set_anti_shake_address(void *base, dma_addr_t val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_ANTI_SHAKE_STAT_MEM_ADD, val);
	PRT_TRACE_END("\n");
}

/* set bgm address for hardware */
void csp_isp_set_bgm_stat_add(void *base, dma_addr_t val)
{
	PRT_TRACE_BEGIN("base=%p,val=0x%08x\n", base, val);
	isp_reg_write(base, ISP_BGM_STAT_MEM_ADD, val);
	PRT_TRACE_END("\n");
}

void csp_isp_dump_regs(void *base, u32 *val)
{
	u32 i = 0, j = 0;

	for (i = 0; i < ARRAY_SIZE(regs_list); ++i) {
		for (j = regs_list[i].start; j <= regs_list[i].end; j = j + 4)
			val[j/4] = isp_reg_read(base, j);
	}
}

void csp_isp_restore_regs(void *base, u32 *val)
{
	u32 i = 0, j = 0;

	for (i = 0; i < ARRAY_SIZE(regs_list); ++i) {
		for (j = regs_list[i].start; j <= regs_list[i].end; j = j + 4)
			isp_reg_write(base, j, val[j/4]);
	}
	/* shadow register */
	csp_isp_set_dma_main_path_add(base,
		val[0x1478/4], val[0x1488/4], val[0x1494/4]);
	csp_isp_set_dma_sub_path_add(base,
		val[0x14a0/4], val[0x14b0/4], val[0x14bc/4]);

	csp_isp_dma_config_update(base);

	csp_isp_set_dma_main_path_add(base,
		val[0x1408/4], val[0x141c/4], val[0x142c/4]);
	csp_isp_set_dma_sub_path_add(base,
		val[0x143c/4], val[0x1450/4], val[0x1460/4]);
	/* update reg */
	isp_reg_set(base, ISP_MAINPATH_CTRL, 3 << 8);
	isp_reg_set(base, ISP_SUBPATH_CTRL, 3 << 8);
	isp_reg_set(base, ISP_DMA_CTRL, 0x3 << 13);
	isp_reg_set(base, ISP_CTRL, 0x7 << 8);
}

void csp_isp_dump_stat(void *base, u32 *val)
{
	u32 i = 0;

	for (i = 0x2414; i <= 0x2450; i = i + 4)
		val[i/4] = isp_reg_read(base, i);

	for (i = 0x2614; i <= 0x2674; i = i + 4)
		val[i/4] = isp_reg_read(base, i);

	for (i = 0x2e54; i <= 0x2ed0; i = i + 4)
		val[i/4] = isp_reg_read(base, i);
}

void csp_isp_dma_start(void *base)
{
	isp_reg_write(base, ISP_DMA_START, 1);
}

void csp_isp_dma_start_ctrl(void *base, u32 val)
{
	isp_reg_write(base, ISP_DMA_START_CTRL, val);
}

u32 lsc_r_data[153] = {[0 ... (153 - 1)] = 1024};
u32 lsc_gr_data[153] = {[0 ... (153 - 1)] = 1024};
u32 lsc_gb_data[153] = {[0 ... (153 - 1)] = 1024};
u32 lsc_b_data[153] = {[0 ... (153 - 1)] = 1024};
u32 r_cnt;
u32 gr_cnt;
u32 gb_cnt;
u32 b_cnt;

int isp_data_set(u32 addr, u32 data)
{
	if ((addr & 0xffff) == 0x2214) {
		if (r_cnt >= 153)
			r_cnt = 0;
		lsc_r_data[r_cnt++] = data;
		return 1;
	} else if ((addr & 0xffff) == 0x2218) {
		if (gr_cnt >= 153)
			gr_cnt = 0;
		lsc_gr_data[gr_cnt++] = data;
		return 1;
	} else if ((addr & 0xffff) == 0x221c) {
		if (b_cnt >= 153)
			b_cnt = 0;
		lsc_b_data[b_cnt++] = data;
		return 1;
	} else if ((addr & 0xffff) == 0x2220) {
		if (gb_cnt >= 153)
			gb_cnt = 0;
		lsc_gb_data[gb_cnt++] = data;
		return 1;
	}
	return 0;
}

int isp_data_get(u32 addr, u32 *data)
{
	if ((addr & 0xffff) == 0x2214) {
		if (r_cnt >= 153)
			r_cnt = 0;
		*data = lsc_r_data[r_cnt++];
		return 1;
	} else if ((addr & 0xffff) == 0x2218) {
		if (gr_cnt >= 153)
			gr_cnt = 0;
		*data = lsc_gr_data[gr_cnt++];
		return 1;
	} else if ((addr & 0xffff) == 0x221c) {
		if (b_cnt >= 153)
			b_cnt = 0;
		*data = lsc_b_data[b_cnt++];
		return 1;
	} else if ((addr & 0xffff) == 0x2220) {
		if (gb_cnt >= 153)
			gb_cnt = 0;
		*data = lsc_gb_data[gb_cnt++];
		return 1;
	}
	return 0;
}

void isp_data_write(void *base)
{
	int i;

	for (i = 0; i < 153; i++) {
		isp_reg_write(base, 0x2214, lsc_r_data[i]);
		isp_reg_write(base, 0x2218, lsc_gr_data[i]);
		isp_reg_write(base, 0x221c, lsc_b_data[i]);
		isp_reg_write(base, 0x2220, lsc_gb_data[i]);
	}
}

/* preisp */
/* get isp dma status */
u32 csp_preisp_get_int_status(void *base)
{
	return 0;
}

/* clear isp dma status */
void csp_preisp_clr_int_status(void *base, u32 status)
{

}

void csp_preisp_set_decompander_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_gamma_fe_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_gamma_be_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_rolloff_r_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_rolloff_g_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_rolloff_b_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_curve_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_hist_gain_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_hist_std_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_local_ccm_lut_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_pregrid_buf_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_ltm_grid_buf_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_aetm_ae_lum_buf_addr(void *base, dma_addr_t addr)
{

}

void csp_preisp_set_aetm_hist_buf_addr(void *base, dma_addr_t addr)
{

}


